using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Text;

namespace Kaleida.ServiceMonitor.Model.Runtime
{
    public static class ReflectionExtensions
    {
        public static bool DerivesFrom(this Type type, Type testAncestor)
        {
            return testAncestor.IsAssignableFrom(type);
        }

        public static bool HasPublicFullyStringParameterisedConstructor(this Type type, int count)
        {
            return GetPublicInstanceConstructors(type).Any(i => AllStringParameters(i) && i.GetParameters().Count() == count);
        }

        public static bool HasPublicFullyStringParameterisedConstructor(this Type type)
        {
            return GetPublicInstanceConstructors(type).Any(AllStringParameters);
        }

        public static IEnumerable<ConstructorInfo> GetOperationConstructors(this Type type)
        {
            return GetPublicInstanceConstructors(type).Where(AllStringParameters);
        }

        public static bool HasPublicDefaultConstructor(this Type type)
        {
            var defaultConstructor = type.GetConstructor(Type.EmptyTypes);
            return defaultConstructor != null && defaultConstructor.IsPublic;
        }

        private static bool AllStringParameters(this ConstructorInfo i)
        {
            return i.GetParameters().All(p => p.ParameterType == typeof(string));
        }

        private static IEnumerable<ConstructorInfo> GetPublicInstanceConstructors(this Type type)
        {
            return type.GetConstructors(BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy);
        }

        internal static string ToPascalCase(this string name)
        {
            var words = name.Split('-');
            return string.Concat(words.Select(i => CultureInfo.InvariantCulture.TextInfo.ToTitleCase(i)));
        }

        internal static string ToDashSeparated(this string name)
        {
            var dashed = new StringBuilder();

            for (int i = 0; i < name.Length; i++ )
            {
                var character = name[i];
                if (Char.IsLower(character))
                    dashed.Append(character);
                else
                {
                    if (i > 0)
                        dashed.AppendFormat("-");

                    dashed.Append(Char.ToLower(character));
                }
            }

            return dashed.ToString();
        }

        internal static string GetPanelName(this Type panelType)
        {
            var panelNameAttribute = (PanelNameAttribute)panelType.GetCustomAttributes(typeof(PanelNameAttribute), false).ToList().FirstOrDefault();
            return panelNameAttribute == null ? panelType.Name : panelNameAttribute.Name;
        }
    }
}